import os
import os.path

import imagehash
import peewee
import wx
from PIL import Image

from event_bus import EventBus
from models import Source, db_proxy, Sample
from uis import SampleSource
from view_models import project_state
from wxutils import call_after
from .preview_panel import PreviewPanel


class SampleSourceMark(SampleSource):
    _accepts = [".png", ".jpg", ".jpeg", ".bmp", ".tga", ".tiff"]
    _ticking = 0
    _ticking_group = 20
    _ticking_fading = 18

    def __init__(self, parent=None):
        super().__init__(parent)

        preview_container = self.remove_sample.GetContainingSizer()
        self.preview = PreviewPanel(self)
        preview_container.Add(self.preview, wx.GBPosition(1, 0), wx.GBSpan(1, 5), wx.ALL | wx.EXPAND, 5)
        preview_container.AddGrowableCol(4)
        preview_container.AddGrowableRow(1)

        self.semiauto_mode.SetValue(False)

        self.Bind(wx.EVT_DIRCTRL_SELECTIONCHANGED, self.load_files, self.dir_list)
        self.Bind(wx.EVT_LISTBOX, self.load_picture, self.file_list)
        self.Bind(wx.EVT_BUTTON, self.signin_sample, self.add_sample)
        self.Bind(wx.EVT_BUTTON, self.signout_sample, self.remove_sample)
        self.Bind(wx.EVT_BUTTON, self.signin_all, self.add_all)
        self.Bind(wx.EVT_BUTTON, self.signout_all, self.remove_all)
        self.Bind(wx.EVT_BUTTON, self.move_to_previous, self.to_prev)
        self.Bind(wx.EVT_BUTTON, self.move_to_next, self.to_next)

        EventBus().register_topic(topic="project_changed", handler=self.update_dir)

    @call_after
    def update_dir(self, _):
        if len(project_state.current.last_source_path) > 0:
            self.dir_list.ExpandPath(project_state.current.last_source_path)

    def load_files(self, _):
        project_state.current.last_source_path = self.dir_list.GetPath()
        project_state.save()
        files = [entry.name
                 for entry in os.scandir(self.dir_list.GetPath())
                 if entry.is_file() and any([entry.name.lower().endswith(suffix)
                                             for suffix in self._accepts])]
        files.sort()
        self.file_list.SetItems(files)
        self.preview.load_image()
        self.add_sample.Enable(False)
        self.remove_sample.Enable(False)

    def move_to_previous(self, _):
        if self.file_list.GetCount() > 0:
            if self.file_list.GetSelection() == wx.NOT_FOUND:
                self.file_list.Select(0)
            elif self.file_list.GetSelection() > 0:
                self.file_list.Select(self.file_list.GetSelection() - 1)
            self.load_picture(None)

    def move_to_next(self, _):
        if self.file_list.GetCount() > 0:
            if self.file_list.GetSelection() == wx.NOT_FOUND:
                self.file_list.Select(0)
            elif self.file_list.GetSelection() < self.file_list.GetCount() - 1:
                self.file_list.Select(self.file_list.GetSelection() + 1)
            self.load_picture(None)

    def _refresh_sign_state(self):
        if self.file_list.GetSelection() != wx.NOT_FOUND:
            selected_file = os.path.join(self.dir_list.GetPath(), self.file_list.GetStringSelection())
            selected_file_fingerprint = str(imagehash.dhash(Image.open(selected_file)))
            is_file_signed = Source.select().where(Source.fingerprint == selected_file_fingerprint).count() > 0
            self.add_sample.Enable(not is_file_signed)
            self.remove_sample.Enable(is_file_signed)

    def load_picture(self, _):
        selected_file_path = os.path.join(self.dir_list.GetPath(), self.file_list.GetStringSelection())
        self.preview.load_image(selected_file_path)
        self._refresh_sign_state()

    def signin_sample(self, _):
        picture = Source()
        picture.path = os.path.join(self.dir_list.GetPath(), self.file_list.GetStringSelection())
        picture.name = self.file_list.GetStringSelection()
        picture.fingerprint = str(imagehash.dhash(Image.open(picture.path)))
        try:
            picture.save()
        except peewee.DatabaseError:
            wx.MessageBox("样本源图缓存失败，源图可能已经存在。", "无法缓存")
        self._refresh_sign_state()
        EventBus().post_topic(None, topic="sample_source_updated")
        if self.semiauto_mode.IsChecked():
            self.move_to_next(None)

    def signin_all(self, _):
        self.switch_timer(None)
        for entry in os.scandir(self.dir_list.GetPath()):
            with db_proxy.atomic():
                if entry.is_file() and any([entry.name.lower().endswith(suffix)
                                            for suffix in self._accepts]):
                    fingerprint = str(imagehash.dhash(Image.open(entry.path)))
                    Source.create(path=entry.path, name=entry.name, fingerprint=fingerprint)
        self._refresh_sign_state()
        EventBus().post_topic(None, topic="sample_source_updated")

    def signout_sample(self, _):
        selected_file = os.path.join(self.dir_list.GetPath(), self.file_list.GetStringSelection())
        selected_file_fingerprint = str(imagehash.dhash(Image.open(selected_file)))
        with db_proxy.atomic():
            Source.delete().where(Source.fingerprint == selected_file_fingerprint).execute()
            Sample.delete().where(Sample.source_fingerprint == selected_file_fingerprint).execute()
        self._refresh_sign_state()
        EventBus().post_topic(None, topic="sample_source_updated")
        if self.semiauto_mode.IsChecked():
            self.move_to_next(None)

    def signout_all(self, _):
        self.switch_timer(None)
        for entry in os.scandir(self.dir_list.GetPath()):
            with db_proxy.atomic():
                if entry.is_file() and any([entry.name.lower().endswith(suffix)
                                            for suffix in self._accepts]):
                    selected_file_fingerprint = str(imagehash.dhash(Image.open(entry.path)))
                    Source.delete().where(Source.fingerprint == selected_file_fingerprint).execute()
                    Sample.delete().where(Sample.source_fingerprint == selected_file_fingerprint).execute()
        self._refresh_sign_state()
        EventBus().post_topic(None, topic="sample_source_updated")
